﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Net.WebSockets;
using System.Collections.Concurrent;
using System.Net.Http;
using Newtonsoft.Json;

namespace SocketService
{
    public class SocketHelper
    {
        /// <summary>
        /// 在线用户字典 <用户ID, Socket>
        /// </summary>
        private static ConcurrentDictionary<string, WebSocket> _sockets = new ConcurrentDictionary<string, WebSocket>();

        /// <summary>
        /// 离线消息队列 <用户ID, 消息列表>
        /// </summary>
        private static ConcurrentDictionary<string, Queue<string>> offlineMessages = new ConcurrentDictionary<string, Queue<string>>();
        private readonly HttpListener _listener;
        private readonly static object _lock = new object();

        public SocketHelper(string prefix)
        {
            _listener = new HttpListener();
            _listener.Prefixes.Add(prefix);
        }

        /// <summary>
        /// 启动socket服务
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task StartAsync(CancellationToken cancellationToken)
        {
            _listener.Start();

            Console.WriteLine($"客户端已连接，当前连接数：{_sockets.Count}");

            while (!cancellationToken.IsCancellationRequested)
            {
                HttpListenerContext context = await _listener.GetContextAsync().ConfigureAwait(false);
                _ = Task.Run(async () =>
                {
                    if (context.Request.IsWebSocketRequest)
                    {
                        HttpListenerWebSocketContext webSocketContext = await context.AcceptWebSocketAsync(null);
                        WebSocket socket = webSocketContext.WebSocket; // 获取 WebSocket 实例

                        // 等待客户端发送用户名（第一条消息）
                        var buffer = new byte[1024 * 4];
                        var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);

                        if (result.MessageType == WebSocketMessageType.Close)
                        {
                            await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "", CancellationToken.None);
                            return;
                        }
                        try
                        {
                            dynamic userInfo = JsonConvert.DeserializeObject<dynamic>(Encoding.UTF8.GetString(buffer, 0, result.Count));

                            AddSocket(userInfo.id.ToString(), socket);
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine("错误：" + ex.Message);
                        }

                        // 这里可以处理 WebSocket 连接
                        _ = Receive(socket, async (result, serializedMessage) =>
                        {
                            if (result.MessageType == WebSocketMessageType.Text)
                            {
                                try
                                {
                                    //Message message = JsonConvert.DeserializeObject<Message>(serializedMessage);
                                    string message = serializedMessage;
                                    Console.WriteLine(message + "---" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                                    //if (message.Contains("getSocketId:"))
                                    //{
                                    //    string socketId = Guid.NewGuid().ToString();
                                    //    //添加指定socket
                                    //    await AddSocket(socketId, socket).ConfigureAwait(false);
                                    //    await SendMessageAsync(socketId, "socketId:" + socketId).ConfigureAwait(false);
                                    //}
                                }
                                catch (Exception)
                                {
                                    socket.Abort();
                                }
                                return;
                            }
                            else if (result.MessageType == WebSocketMessageType.Close)
                            {
                                try
                                {
                                    await OnDisconnected(socket);
                                    var id = GetId(socket);
                                    Console.WriteLine($"客户端{id}断开连接，当前连接数：{_sockets.Count}");
                                }
                                catch (WebSocketException)
                                {
                                    throw; //let's not swallow any exception for now
                                }
                                return;
                            }
                        });
                    }
                    else
                    {
                        ProcessHttpRequest(context);
                    }
                });

            }
        }

        /// <summary>
        /// 信息处理
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="handleMessage"></param>
        /// <returns></returns>
        private async Task Receive(WebSocket socket, Action<WebSocketReceiveResult, string> handleMessage)
        {
            // 判断连接类型，并执行相应操作
            while (socket.State == WebSocketState.Open)
            {
                ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[1024 * 4]);
                string message = null;
                WebSocketReceiveResult result = null;
                try
                {
                    using (var ms = new MemoryStream())
                    {
                        do
                        {
                            // 继续接受信息
                            result = await socket.ReceiveAsync(buffer, CancellationToken.None).ConfigureAwait(false);
                            ms.Write(buffer.Array, buffer.Offset, result.Count);
                        }
                        while (!result.EndOfMessage);

                        ms.Seek(0, SeekOrigin.Begin);

                        using (var reader = new StreamReader(ms, Encoding.UTF8))
                        {
                            message = await reader.ReadToEndAsync().ConfigureAwait(false);
                        }
                    }

                    handleMessage(result, message);
                }
                catch (WebSocketException e)
                {
                    if (e.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely)
                    {
                        socket.Abort();
                    }
                }
            }

            await OnDisconnected(socket);
        }

        /// <summary>
        /// http请求
        /// </summary>
        /// <param name="context"></param>
        private static void ProcessHttpRequest(HttpListenerContext context)
        {
            if (context.Request.HttpMethod == "GET" && context.Request.Url.AbsolutePath == "/api/clients")
            {
                // 返回当前连接的客户端信息
                var response = context.Response;
                response.ContentType = "application/json";

                lock (_lock)
                {
                    var clientList = new List<string>(_sockets.Keys);
                    var jsonResponse = System.Text.Json.JsonSerializer.Serialize(clientList);
                    var buffer = Encoding.UTF8.GetBytes(jsonResponse);

                    response.ContentLength64 = buffer.Length;
                    response.OutputStream.Write(buffer, 0, buffer.Length);
                }

                response.Close();
            }
            else
            {
                context.Response.StatusCode = 404;
                context.Response.Close();
            }
        }

        /// <summary>
        /// 发送给所有的socket
        /// </summary>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task SendAllMessageAsync(object message)
        {
            foreach (var socket in _sockets)
            {
                if (socket.Value.State != WebSocketState.Open)
                    return;
                var serializedMessage = JsonConvert.SerializeObject(message);
                var encodedMessage = Encoding.UTF8.GetBytes(serializedMessage);
                try
                {
                    await socket.Value.SendAsync(buffer: new ArraySegment<byte>(array: encodedMessage,
                                                                          offset: 0,
                                                                          count: encodedMessage.Length),
                                           messageType: WebSocketMessageType.Text,
                                           endOfMessage: true,
                                           cancellationToken: CancellationToken.None).ConfigureAwait(false);
                }
                catch (WebSocketException e)
                {
                    if (e.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely)
                    {
                        await OnDisconnected(socket.Value);
                    }
                }
            }
        }

        /// <summary>
        /// 发送消息给指定id的socket
        /// </summary>
        /// <param name="socketId"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task SendMessageAsync(string socketId, string message)
        {
            var socket = GetSocketById(socketId);
            if (socket != null)
                await SendMessageAsync(socket, message).ConfigureAwait(false);
        }

        /// <summary>
        /// 发送消息给指定 socket
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public async Task SendMessageAsync(WebSocket socket, string message)
        {
            if (socket.State != WebSocketState.Open)
                return;
            var serializedMessage = JsonConvert.SerializeObject(message);
            var encodedMessage = Encoding.UTF8.GetBytes(serializedMessage);
            try
            {
                await socket.SendAsync(buffer: new ArraySegment<byte>(array: encodedMessage,
                                                                      offset: 0,
                                                                      count: encodedMessage.Length),
                                       messageType: WebSocketMessageType.Text,
                                       endOfMessage: true,
                                       cancellationToken: CancellationToken.None).ConfigureAwait(false);
            }
            catch (WebSocketException e)
            {
                if (e.WebSocketErrorCode == WebSocketError.ConnectionClosedPrematurely)
                {
                    await OnDisconnected(socket);
                }
            }
        }

        /// <summary>
        /// 添加socket连接
        /// </summary>
        /// <param name="socket"></param>
        public void AddSocket(string socketId, WebSocket socket)
        {
            Console.WriteLine($"已将ID用户“{socketId}”添加到Socket中");
            _sockets.TryAdd(socketId, socket);
            Console.WriteLine($"当前连接数：{_sockets.Count()}");
        }

        /// <summary>
        /// 获取指定id的socket
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public WebSocket GetSocketById(string id)
        {
            if (_sockets.TryGetValue(id, out WebSocket socket))
                return socket;
            else
                return null;
        }

        /// <summary>
        /// 断开socket连接
        /// </summary>
        /// <param name="socket"></param>
        /// <returns></returns>
        public virtual async Task OnDisconnected(WebSocket socket)
        {
            var socketId = GetId(socket);
            if (!string.IsNullOrWhiteSpace(socketId))
                await RemoveSocket(socketId).ConfigureAwait(false);
        }

        /// <summary>
        /// 根据 socket 获取其id
        /// </summary>
        /// <param name="socket"></param>
        /// <returns></returns>
        public string GetId(WebSocket socket)
        {
            return _sockets.FirstOrDefault(p => p.Value == socket).Key;
        }

        /// <summary>
        /// 删除指定 id 的 socket，并关闭连接
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task RemoveSocket(string id)
        {
            if (id == null) return;

            if (_sockets.TryRemove(id, out WebSocket socket))
            {
                if (socket.State != WebSocketState.Open) return;

                await socket.CloseAsync(closeStatus: WebSocketCloseStatus.NormalClosure,
                                        statusDescription: "Closed by the WebSocketManager",
                                        cancellationToken: CancellationToken.None).ConfigureAwait(false);
            }
        }
    }
}
